"""
音频设备切换测试工具
用于测试 AudioService 在切换设备后能否立即应用到当前播放的音频
"""
import os
import sys
import time
import logging
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
    QPushButton, QLabel, QComboBox, QFileDialog, QGroupBox, 
    QMessageBox, QTextEdit, QListWidget
)
from PyQt5.QtCore import Qt, QTimer

# 确保可以导入 AudioService
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(current_dir)
sys.path.append(parent_dir)
from app.services.service_locator import ServiceLocator
from app.services.audio_service import IAudioService
from app.services.audio_service_impl import AudioService
from app.models.audio_item import AudioItem

# 设置日志配置
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

class LogHandler(logging.Handler):
    """自定义日志处理器，将日志输出到GUI"""
    
    def __init__(self, text_edit):
        super().__init__()
        self.text_edit = text_edit
        self.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
        
    def emit(self, record):
        msg = self.format(record)
        self.text_edit.append(msg)


class DeviceSwitchTestWindow(QMainWindow):
    """
    音频设备切换测试窗口
    """
    
    def __init__(self):
        super().__init__()
        
        # 初始化变量
        self.current_file = None
        self.timer = None
        self.audio_service = None
        self.current_audio_item = None
        
        # 初始化窗口
        self.initUI()
        
        # 初始化音频服务
        self.init_audio_service()
        
        # 加载音频设备
        self.load_audio_devices()
    
    def initUI(self):
        """初始化UI界面"""
        # 设置窗口标题和大小
        self.setWindowTitle('音频设备切换测试工具')
        self.resize(600, 600)
        
        # 创建主布局
        main_layout = QVBoxLayout()
        
        # === 设备选择部分 ===
        device_group = QGroupBox('音频设备')
        device_layout = QVBoxLayout()
        
        device_header = QHBoxLayout()
        device_label = QLabel('输出设备:')
        self.device_combo = QComboBox()
        self.device_combo.currentIndexChanged.connect(self.device_changed)
        self.refresh_btn = QPushButton('刷新')
        self.refresh_btn.clicked.connect(self.load_audio_devices)
        
        device_header.addWidget(device_label)
        device_header.addWidget(self.device_combo, 1)
        device_header.addWidget(self.refresh_btn)
        device_layout.addLayout(device_header)
        
        device_group.setLayout(device_layout)
        main_layout.addWidget(device_group)
        
        # === 文件选择部分 ===
        file_group = QGroupBox('音频文件')
        file_layout = QHBoxLayout()
        
        self.file_label = QLabel('未选择文件')
        self.file_btn = QPushButton('选择文件')
        self.file_btn.clicked.connect(self.select_file)
        
        file_layout.addWidget(self.file_label, 1)
        file_layout.addWidget(self.file_btn)
        
        file_group.setLayout(file_layout)
        main_layout.addWidget(file_group)
        
        # === 播放控制部分 ===
        control_group = QGroupBox('播放控制')
        control_layout = QHBoxLayout()
        
        self.play_btn = QPushButton('播放')
        self.play_btn.clicked.connect(self.play_audio)
        
        self.stop_btn = QPushButton('停止')
        self.stop_btn.clicked.connect(self.stop_audio)
        
        control_layout.addWidget(self.play_btn)
        control_layout.addWidget(self.stop_btn)
        
        control_group.setLayout(control_layout)
        main_layout.addWidget(control_group)
        
        # === 设备测试部分 ===
        test_group = QGroupBox('设备测试')
        test_layout = QVBoxLayout()
        
        self.device_list = QListWidget()
        self.update_devices_btn = QPushButton('更新设备列表')
        self.update_devices_btn.clicked.connect(self.update_device_list)
        
        test_layout.addWidget(self.device_list)
        test_layout.addWidget(self.update_devices_btn)
        
        test_group.setLayout(test_layout)
        main_layout.addWidget(test_group)
        
        # === 状态显示部分 ===
        self.status_label = QLabel('状态: 就绪')
        main_layout.addWidget(self.status_label)
        
        # === 日志显示部分 ===
        log_group = QGroupBox('日志输出')
        log_layout = QVBoxLayout()
        
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        log_layout.addWidget(self.log_text)
        
        log_group.setLayout(log_layout)
        main_layout.addWidget(log_group)
        
        # 设置中央窗口部件
        central_widget = QWidget()
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)
        
        # 添加日志处理器
        log_handler = LogHandler(self.log_text)
        logger = logging.getLogger()
        logger.addHandler(log_handler)
        logger.setLevel(logging.INFO)
    
    def init_audio_service(self):
        """初始化音频服务"""
        try:
            # 创建音频服务
            self.audio_service = AudioService()
            
            # 初始化音频服务
            self.audio_service.initialize()
            
            # 注册音频服务到服务定位器
            ServiceLocator.register(IAudioService, self.audio_service)
            
            # 添加事件监听
            self.audio_service.add_listener("audio_playback_started", self.on_playback_started)
            self.audio_service.add_listener("audio_playback_completed", self.on_playback_completed)
            self.audio_service.add_listener("audio_playback_error", self.on_playback_error)
            self.audio_service.add_listener("audio_device_changed", self.on_device_changed)
            
            logging.info("音频服务初始化成功")
        except Exception as e:
            logging.error(f"初始化音频服务失败: {str(e)}")
            import traceback
            logging.error(f"异常堆栈: {traceback.format_exc()}")
            QMessageBox.critical(self, "错误", f"初始化音频服务失败: {str(e)}")
    
    def load_audio_devices(self):
        """加载音频设备列表"""
        try:
            # 保存当前选中的设备名称
            current_device = self.device_combo.currentText() if self.device_combo.count() > 0 else None
            
            # 清空设备列表
            self.device_combo.clear()
            
            # 获取设备列表
            devices = self.audio_service.get_output_devices()
            
            # 添加设备到下拉框
            for device in devices:
                self.device_combo.addItem(device)
            
            # 恢复之前选择的设备
            if current_device:
                index = self.device_combo.findText(current_device)
                if index >= 0:
                    self.device_combo.setCurrentIndex(index)
            
            # 更新设备列表
            self.update_device_list()
            
            logging.info(f"加载了 {len(devices)} 个音频输出设备")
        except Exception as e:
            logging.error(f"加载音频设备失败: {str(e)}")
            QMessageBox.warning(self, "警告", f"加载音频设备失败: {str(e)}")
    
    def update_device_list(self):
        """更新设备列表"""
        try:
            self.device_list.clear()
            devices = self.audio_service.get_output_devices()
            for device in devices:
                self.device_list.addItem(device)
            logging.info(f"更新设备列表: {len(devices)} 个设备")
        except Exception as e:
            logging.error(f"更新设备列表失败: {str(e)}")
    
    def device_changed(self):
        """设备变更处理"""
        try:
            index = self.device_combo.currentIndex()
            if index >= 0:
                device_name = self.device_combo.currentText()
                
                # 设置当前输出设备
                if hasattr(self, 'audio_service'):
                    # 使用公共接口设置设备
                    self.audio_service.set_output_device(device_name)
                    logging.info(f"请求切换输出设备为: {device_name}")
        except Exception as e:
            logging.error(f"切换设备失败: {str(e)}")
    
    def select_file(self):
        """选择音频文件"""
        try:
            file_path, _ = QFileDialog.getOpenFileName(
                self, "选择音频文件", "", 
                "音频文件 (*.wav *.mp3 *.ogg *.flac *.aac *.m4a);;所有文件 (*.*)"
            )
            
            if file_path:
                self.current_file = file_path
                self.file_label.setText(os.path.basename(file_path))
                self.status_label.setText(f"状态: 已选择文件 {os.path.basename(file_path)}")
                logging.info(f"已选择音频文件: {file_path}")
        except Exception as e:
            logging.error(f"选择文件失败: {str(e)}")
    
    def play_audio(self):
        """播放音频"""
        try:
            if not self.current_file:
                QMessageBox.warning(self, "警告", "请先选择一个音频文件")
                return
            
            # 创建音频项
            audio_item = AudioItem(
                id=os.path.basename(self.current_file),
                title=os.path.basename(self.current_file),
                file_path=self.current_file
            )
            
            # 保存当前音频项
            self.current_audio_item = audio_item
            
            # 播放音频，使用play_item方法而不是play方法
            self.audio_service.play_item(audio_item)
            self.status_label.setText(f"状态: 正在播放 {os.path.basename(self.current_file)}")
            logging.info(f"开始播放: {self.current_file}")
        except Exception as e:
            logging.error(f"播放失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"播放失败: {str(e)}")
    
    def stop_audio(self):
        """停止音频播放"""
        try:
            self.audio_service.stop()
            self.status_label.setText("状态: 已停止")
            logging.info("播放已停止")
        except Exception as e:
            logging.error(f"停止播放失败: {str(e)}")
    
    def on_playback_started(self, event):
        """播放开始回调"""
        audio_item = event.data
        self.status_label.setText(f"状态: 正在播放 {audio_item.title}")
        logging.info(f"播放开始: {audio_item.title}")
    
    def on_playback_completed(self, event):
        """播放完成回调"""
        audio_item = event.data
        self.status_label.setText(f"状态: 播放完成 {audio_item.title}")
        logging.info(f"播放完成: {audio_item.title}")
    
    def on_playback_error(self, event):
        """播放错误回调"""
        error = event.data.get("error", "未知错误")
        self.status_label.setText(f"状态: 播放错误 - {error}")
        logging.error(f"播放错误: {error}")
    
    def on_device_changed(self, event):
        """设备变更回调"""
        data = event.data
        old_device = data.get("old_device", "未知")
        new_device = data.get("new_device", "未知")
        logging.info(f"设备变更: {old_device} -> {new_device}")
    
    def closeEvent(self, event):
        """关闭窗口事件处理"""
        try:
            # 停止播放
            if hasattr(self, 'audio_service'):
                self.audio_service.stop()
            
            event.accept()
        except Exception as e:
            logging.error(f"关闭窗口异常: {str(e)}")


def main():
    """程序入口函数"""
    # 设置高DPI缩放
    QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
    QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
    
    app = QApplication(sys.argv)
    window = DeviceSwitchTestWindow()
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main() 